package se.gala.sessions;

import java.io.Closeable;
import java.util.HashMap;

import se.gala.core.Agora;
import se.gala.users.Player;
import se.gala.users.PlayerBalance;
import se.gala.utils.GGObject;
import se.gala.utils.Storable;

public class PlayerSession extends GGObject implements Closeable, Storable {
	
	private SessionToken token;
	private String username;
	private boolean active = false;
	private Player player;
	
	public static final int MIN_USERNAME_LENGTH = 1; 
	public static final int MIN_PASSWORD_LENGTH = 1;
	public static final int ACTIVE_SESSIONS_INITIAL_CAPACITY = 1000;
	
	public static enum PlayerRestrictionStates {NoRestriction, SelfExclusion, FrozenAccount, SessionLimits, BlockedIP, BlockedCountry};
	private static HashMap<String, PlayerSession> activeSessions = new HashMap<String, PlayerSession>(ACTIVE_SESSIONS_INITIAL_CAPACITY); 

	private PlayerSession(String username) throws PlayerRestrictionException {
		this.username = username;
		final PlayerRestrictionStates restrictionState = checkPlayerRestrictions();
		if (restrictionState != PlayerRestrictionStates.NoRestriction) {
			throw new PlayerRestrictionException(restrictionState);
		}
		setPlayer();
		setToken();
		registerInActiveSessions();
	}
	
	protected void setPlayer() {
		// DUMMY implement proper setPlayer() within PlayerSession
		player = Player.initiatePlayer(username);
	}

	public static PlayerSession authenticatePlayer(String username, String password) throws AuthenticationException {
		if (username.length() < MIN_USERNAME_LENGTH || password.length() < MIN_PASSWORD_LENGTH) {
			throw new BadPlayerCredentials();
		} else if (validatePlayerCredentials(username, password) == false) {
			throw new PlayerNotFoundException();
		}
		return new PlayerSession(username);
	}
	
	public static PlayerSession getSessionByToken(String username, String token) throws AuthenticationException {
		final PlayerSession ps = getPlayerSessionByToken(token);
		if (ps == null) {
			throw new SessionExpiredException();			
		} else if (validatePlayerCredentials(username, ps.getToken()) == false) {
			throw new PlayerNotFoundException();
		}
		return ps;
	}
	
	public static boolean closeSession(String username, String token) {
		boolean success;
		try {
			PlayerSession ps = getSessionByToken(username, token);
			ps.close();
			success = true;
		} catch (AuthenticationException e) {
//			e.printStackTrace();
			success = false;
		}
		return success;
	}
	
	final public void close() {
		active = false;
		activeSessions.remove(username);
	}
	
	final public PlayerBalance getPlayerBalance() {
		return player.getBalance();
	}
	
	private static boolean validatePlayerCredentials(String username, SessionToken sessionToken) {
		return username.equals(sessionToken.getUser());
	}
	
	private static boolean validatePlayerCredentials(String username, String password) {
		// DUMMY 'player validation' implementation
		if (username.equals(Agora.DUMMY_username_valid) && password.equals(Agora.DUMMY_password_valid)) {
			return true;
		} else {
			return false;
		}
	}
	
	protected PlayerRestrictionStates checkPlayerRestrictions() {
		// DUMMY 'player restriction check' implementation
		return PlayerRestrictionStates.NoRestriction;		
	}
	
	final public SessionToken getToken() {
		return token;
	}
	
	final public Player getPlayer() {
		return player;
	}
	
	final public boolean isActive() {
		return active;
	}
	
	final private void setToken() {
		token = new SessionToken("st" + System.currentTimeMillis() + username, username);
	}
	
	final protected static PlayerSession getPlayerSessionByToken(String token) {
		return activeSessions.get(token);
	}
	
	final protected void registerInActiveSessions() {
		this.active = true;
		activeSessions.put(token.getValue(), this);
	}
}
